﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using POP.Mime.Decode;

namespace POP.Mime.Header
{
	// Class that hold information about one "Received:" header line.<br/>
	public class Received
	{
		// The date of this received line.
		public DateTime Date { get; private set; }

		public Dictionary<string, string> Names { get; private set; }

		// The raw input string that was parsed into this class.
		public string Raw { get; private set; }

		// Parses a Received header value.
		public Received(string headerValue)
		{
			if (headerValue == null)
				throw new ArgumentNullException("headerValue");

			// Remember the raw input if someone whishes to use it
			Raw = headerValue;

			// Default Date value
			Date = DateTime.MinValue;

			// The date part is the last part of the string, and is preceeded by a semicolon
			// Some emails forgets to specify the date, therefore we need to check if it is there
			if(headerValue.Contains(";"))
			{
				string datePart = headerValue.Substring(headerValue.LastIndexOf(";") + 1);
				Date = Rfc2822DateTime.StringToDate(datePart);
			}

			Names = ParseDictionary(headerValue);	
		}

		// Parses the Received header name-value-list into a dictionary.
		private static Dictionary<string, string> ParseDictionary(string headerValue)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();

			// Remove the date part from the full headerValue if it is present
			string headerValueWithoutDate = headerValue;
			if (headerValue.Contains(";"))
			{
				headerValueWithoutDate = headerValue.Substring(0, headerValue.LastIndexOf(";"));
			}

			// Reduce any whitespace character to one space only
			headerValueWithoutDate = Regex.Replace(headerValueWithoutDate, @"\s+", " ");

			const string pattern = @"(?<name>[^\s]+)\s(?<value>[^\s]+(\s\(.+?\))*)";

			// Find each match in the string
			MatchCollection matches = Regex.Matches(headerValueWithoutDate, pattern);
			foreach (Match match in matches)
			{
				// Add the name and value part found in the matched result to the dictionary
				string name = match.Groups["name"].Value;
				string value = match.Groups["value"].Value;

				// Check if the name is really a comment.
				// In this case, the first entry in the header value
				// is a comment
				if (name.StartsWith("("))
				{
					continue;
				}

				// Only add the first name pair
				// All subsequent pairs are ignored, as they are invalid anyway
				if(!dictionary.ContainsKey(name))
					dictionary.Add(name, value);
			}

			return dictionary;
		}
	}
}